#include "SmileProfile.h"

#include <string.h>
#include <math.h>
#include <ctype.h>

#include <iostream>
#include <fstream>
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
#define  NumberCharacter 34
#define  LENGTH_LINGO    4
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
SmileProfile::SmileProfile():filename(NULL), numberSmiles(0), smiles(NULL), frecLingos(NULL), posAfterOrderLingos(NULL), numberLingos(0) {}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
SmileProfile::~SmileProfile() {

  if (filename)             delete[] filename;
  for (int i = 0; i < numberSmiles; i++) 
    if (smiles[i])          delete[] smiles[i];  
  if (smiles)               delete[] smiles;
  if (frecLingos)           delete[] frecLingos;
  if (posAfterOrderLingos)  delete[] posAfterOrderLingos;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::Filename(char *filename_tmp) {

  if (filename) delete[] filename;
  filename = new char[strlen(filename_tmp) + 1];
  strcpy(filename, filename_tmp);

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::NumberSmiles(int numberSmiles_tmp) {

  numberSmiles = numberSmiles_tmp;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::Smiles(char **smiles_tmp, int numberSmiles_tmp) {

  if (numberSmiles_tmp < 0) return;

  for (int i = 0; i < numberSmiles; i++) 
    if (smiles[i]) delete[] smiles[i];
  if (smiles) delete[] smiles;

  numberSmiles = numberSmiles_tmp;
  smiles = new char*[numberSmiles_tmp];

  for (int i = 0; i < numberSmiles_tmp; i++) {
    smiles[i] = new char[strlen(smiles_tmp[i]) + 1];
    strcpy(smiles[i], smiles_tmp[i]);	
  }

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::FrecLingos(int *frecLingos_tmp, int numberSmiles_tmp) {

  if (numberSmiles_tmp < 0) return;
  if (frecLingos) delete[] frecLingos;
  frecLingos = new int[numberSmiles_tmp];
  for (int i = 0; i < numberSmiles_tmp; i++)
    frecLingos[i] = frecLingos_tmp[i];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::PosAfterOrderLingos(int *posAfterOrderLingos_tmp, int numberSmiles_tmp) {

  if (numberSmiles_tmp < 0) return;
  if (posAfterOrderLingos) delete[] posAfterOrderLingos;
  posAfterOrderLingos = new int[numberSmiles_tmp];
  for (int i = 0; i < numberSmiles_tmp; i++)
    posAfterOrderLingos[i] = posAfterOrderLingos_tmp[i];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::NumberLingos(int numberLingos_tmp) {

  numberLingos = numberLingos_tmp;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
char* SmileProfile::Filename(void) {

  return filename;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::NumberSmiles(void) {

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
char* SmileProfile::Smiles(int pos) {

  if (pos < 0 || pos >= numberSmiles) return NULL;
  return smiles[pos];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::FrecLingos(int pos) {

  if (pos < 0 || pos >= numberLingos) return -1;
  return frecLingos[pos];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::PosAfterOrderLingos(int pos) {

  if (pos < 0 || pos >= numberLingos) return -1;
  return posAfterOrderLingos[pos];

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::NumberLingos(void) {

  return numberLingos;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::ComputeLingo4Code(char *lingo_tmp) {

  if (!lingo_tmp || (strlen(lingo_tmp) != 4)) return -1;

  //Cl -> L; Br -> R; numbers -> ?
  char lingoCharacter[NumberCharacter] = {'C', 'O', 'H', 'N', 'S', 'F', 'L', 'R', 'P', 'I', 'B', '(', ')', '=', '#', '-', '@', '[', ']', '\\', '/', '+', '?', 'c', 'o', 'h', 'n', 's', 'f', 'p', 'i', 'b'};
  /*---------------------------------------0----1----2----3----4----5----6----7----8----9----10---11---12---13---14---15---16---17---18---19---20---22---23---24---35---26---27---28---30---31---32---33*/

  int pos1, pos2, pos3, pos4, positionList, count = 0; 
  bool condition = false;

  positionList = pos1 = pos2 = pos3 = pos4 = -1;

  while (!condition && count < NumberCharacter) {

    pos1 = (lingo_tmp[0] == lingoCharacter[count])?count:pos1;
    pos2 = (lingo_tmp[1] == lingoCharacter[count])?count:pos2;
    pos3 = (lingo_tmp[2] == lingoCharacter[count])?count:pos3;
    pos4 = (lingo_tmp[3] == lingoCharacter[count])?count:pos4;
    count++;
    condition = ((pos1 != -1) && (pos2 != -1) && (pos3 != -1) && (pos4 != -1))?true:condition;

  }

  positionList =  pos1 * pow(NumberCharacter, 3) + pos2 * pow(NumberCharacter, 2) + pos3 * NumberCharacter + pos4;

  return positionList;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
char *SmileProfile::ComputeLingo4Code(int position) {
  
  if (position < 0 || position > pow(NumberCharacter, 4)) return NULL;

  //Cl -> L; Br -> R; numbers -> ?
  char lingoCharacter[NumberCharacter] = {'C', 'O', 'H', 'N', 'S', 'F', 'L', 'R', 'P', 'I', 'B', '(', ')', '=', '#', '-', '@', '[', ']', '\\', '/', '+', '?', 'c', 'o', 'h', 'n', 's', 'f', 'p', 'i', 'b'};
  /*---------------------------------------0----1----2----3----4----5----6----7----8----9----10---11---12---13---14---15---16---17---18---19---20---22---23---24---35---26---27---28---30---31---32---33*/

  char *lingo_tmp = new char[5];

  lingo_tmp[0] = lingoCharacter[(int)(position/(int)pow(NumberCharacter, 3))];
  position     = (int)(position%(int)pow(NumberCharacter, 3));
  lingo_tmp[1] = lingoCharacter[(int)(position/(int)pow(NumberCharacter, 2))];
  position     = (int)(position%(int)pow(NumberCharacter, 2));
  lingo_tmp[2] = lingoCharacter[(int)(position/NumberCharacter)];
  lingo_tmp[3] = lingoCharacter[(int)(position%NumberCharacter)];
  lingo_tmp[4] = '\0';

  return lingo_tmp;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::ExtractSmiles(void) {

  if (!filename) return 0;

  ifstream  filestr;
  filestr.open (filename, ios::in);
  if (!filestr.is_open()) return 0;

  char    *lineInput = new char[1000];
  int      numberLine = 0;

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    if (strlen(lineInput)) numberLine++;
  }

  for (int i = 0; i < numberSmiles; i++) 
    if (smiles[i]) delete[] smiles[i];
  if (smiles) delete[] smiles;

  numberSmiles = numberLine;
  smiles = new char*[numberSmiles];
  numberLine = 0;

  filestr.close();
  filestr.open (filename, ios::in);

  while (!filestr.eof()) {
    filestr.getline(lineInput, 1000);
    char *part = strtok(lineInput, " ");
    if (!part) continue;
    smiles[numberLine] = new char[strlen(part) + 1];
    strcpy(smiles[numberLine++], part);
  }
  filestr.close();

  delete[] lineInput;

  long sizeLingosArr = pow(NumberCharacter, LENGTH_LINGO);
  frecLingos          = new int[sizeLingosArr];
  posAfterOrderLingos = new int[sizeLingosArr];
  for (int i = 0; i < sizeLingosArr; i++) {
      posAfterOrderLingos[i]  = i;
      frecLingos[i]           = 0;
  }

  return numberSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::CreateLingosProfile(void) {

  ExtractSmiles();
  printf("Finish ExtractSmiles Process...\n");
  for (int i = 0; i < numberSmiles; i++) LingosProfSmiles(i);
  printf("Finish CreateLingosProfile Process...\n");
  numberLingos = pow(NumberCharacter, LENGTH_LINGO);
  CompactLingosProfile();
  printf("Finish CompactLingosProfile Process...\n");
  
}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::CompactLingosProfile(void) {

  //

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::LingosProfSmiles(int position) {

  if (position < 0 || position >= numberSmiles) return -1;

  char *temporal_code = new char[strlen(smiles[position]) + 1], *part;
  strcpy(temporal_code, smiles[position]);
  numberLingos = 0;

  ReduceLingo4(temporal_code, "Cl", "L ");
  ReduceLingo4(temporal_code, "Br", "R ");
  ReduceLingo4Number(temporal_code);

  for (int i = 0; i < strlen(temporal_code); i++)
    if (temporal_code[i] != ' ') temporal_code[numberLingos++] = temporal_code[i];
  temporal_code[numberLingos] = '\0';
  numberLingos -= LENGTH_LINGO - 1;

  if (numberLingos) {
    char lingos[5];
    for (int i = 0; i < numberLingos; i++) {
      CopyLingo(lingos, temporal_code, i, i+4);
      int valueRef = ComputeLingo4Code(lingos);
      if (valueRef < 0) { printf("Error (%s)\n", lingos); }
      frecLingos[valueRef]++;
    }
  }
  else {
    if (strlen(temporal_code) > 3) {
      int valueRef = ComputeLingo4Code(temporal_code);
      if (valueRef < 0) { printf("Error (%s)\n", temporal_code); }
      frecLingos[valueRef]++;
      numberLingos = 1;
    }
  }

  delete[] temporal_code;

  return numberLingos;

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::CopyLingo(char *lingo, char* line, int start, int end) {

  int i, j;
  for (i = start, j = 0; i < end; i++) lingo[j++] = line[i];
  lingo[j] = '\0';

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::ReduceLingo4(char *lingo, const char *find, const char *replace) {
    
  //Change of Cl and Br for
  char *part = NULL;
  part = strstr(lingo, find);
  
  if (part)
    strncpy(part, replace, strlen(find));
  while (part) {
    part = strstr(lingo, find);
    if (part) strncpy(part, replace, strlen(find));
  }

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
void SmileProfile::ReduceLingo4Number(char *lingo) {

  ReduceLingo4(lingo, "1", "?");
  ReduceLingo4(lingo, "2", "?");
  ReduceLingo4(lingo, "3", "?");
  ReduceLingo4(lingo, "4", "?");
  ReduceLingo4(lingo, "5", "?");
  ReduceLingo4(lingo, "6", "?");
  ReduceLingo4(lingo, "7", "?");
  ReduceLingo4(lingo, "8", "?");
  ReduceLingo4(lingo, "9", "?");
  ReduceLingo4(lingo, "0", "?");

}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::AlphabetSize(void) {
    
    return NumberCharacter;
   
}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
int SmileProfile::LingoLength(void) {

    return LENGTH_LINGO;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------
